/ 407
Table Of Contents
1
Developing
with
the
SharePoint
Framework
Version: December 2018
Visit the U2U website
www.u2u.be
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
2
Table Of Contents
Copyright © 2000-2018 U2U Training nv/sa, B-1731 Zellik (Brussels), Belgium.
Niets uit dit document mag worden verveelvoudigd en/of openbaar gemaakt door middel van druk,
fotokopie, microfilm, elektronisch of op welke andere wijze ook en evenmin in een retrieval systeem
worden opgeslagen zonder voorafgaande schriftelijke toestemming van de auteur.
Hoewel dit document met zeer veel zorg is samengesteld, aanvaarden de auteurs geen enkele
aansprakelijkheid voor schade ontstaan door eventuele fouten en/of onvolkomenheden in dit
document.
Copyright © 2000-2018 U2U Training nv/sa, B-1731 Zellik (Brussels), Belgium.
No part of this document may be reproduced or transmitted in any form or by any means, electronic
or mechanical, for any purpose, without the express written permission of the author.
This publication is provided "as is" without warranty of any kind, either express or implied, including,
but not limited to, the implied warranties of merchantability, fitness for a particular purpose, or non-
infringement.
This publication could include technical inaccuracies or typographical errors. Changes are periodically
added to the information herein; these changes will be incorporated in new editions of the
publication.
Published by U2U Training nv/sa, B-1731 Zellik (Brussels), Belgium
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
Table Of Contents
3
1
TABLE OF CONTENTS
1
TABLE OF CONTENTS...............................................................................................................3
2
SHAREPOINT FRAMEWORK................................................................................................13
2.1
What is SharePoint Framework......................................................................................... 14
2.2
Why SharePoint Framework? ........................................................................................... 18
2.3
Modern toolchain ............................................................................................................ 20
2.4
The Future ....................................................................................................................... 26
2.5
More Info......................................................................................................................... 27
3
PREPARING YOUR MACHINE ..............................................................................................28
3.1
Setup Office 365............................................................................................................... 29
3.2
Software Installation........................................................................................................ 30
3.3
LAB Get ready for the Sharepoint Framework................................................................. 33
3.3.1
Setup a tenant..................................................................................................................... 33
3.3.2
Setup your machine ............................................................................................................ 33
4
MODULES...................................................................................................................................34
4.1
Creating a Project............................................................................................................. 35
4.2
Using Modules ................................................................................................................. 37
4.3
CommonJS....................................................................................................................... 40
4.4
Important Modules .......................................................................................................... 43
5
FRAMEWORK CLIENT WEB PARTS...................................................................................44
5.1
What is a Client Web Part? ............................................................................................... 45
5.2
Creating a project............................................................................................................. 47
5.3
Exploring Project Contents ............................................................................................... 48
5.4
Running Your Project........................................................................................................ 54
5.5
Gulp tasks........................................................................................................................ 56
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
Loading SharePoint Data
179
ISPDATASERVICE.TS
import {ISPList} from './ISPList';
export interface ISPDataService{
getLists():ISPList[];
}
Let’s now use the data service interface and create our mock service first.
Create a new folder services inside the src folder.
Inside the services folder, create a MockDataService.ts file. We will return a simple collection of
mock lists as data in case we are working offline.
MOCKDATASERVICE.TS
import { ISPList } from '../interfaces/ISPList';
import { ISPDataService } from '../interfaces/ISPDataService';
export default class MockDataService implements ISPDataService {
public getLists(): ISPList[] {
var mockData: ISPList[] = [
{ id: "1", name: "Announcements" },
{ id: "2", name: "Calendar" }
];
return mockData;
}
}
Let’s already test this. In the webpart we will load a new instance of our mock data service and get
the mock data. Also, we will provide a method getListDropdownOptions that converts the data to
actual dropdown option objects.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
180
Loading SharePoint Data
LISTDATAWEBPART.TS
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneDropdown,
PropertyPaneSlider,
IPropertyPaneDropdownOption
} from '@microsoft/sp-webpart-base';
import { ISPList } from '../../interfaces/ISPList';
import { ISPDataService } from '../../interfaces/ISPDataService';
import MockDataService from '../../services/MockDataService';
export default class ListDataWebPart extends {
private getLists(): ISPList[]{
let dataService = new MockDataService();
let listData: ISPList[] = dataService.getLists();
return listData;
}
private getListDropdownOptions(): IPropertyPaneDropdownOption[]{
var listData: ISPList[] = this.getLists();
var ddOptions: IPropertyPaneDropdownOption[] = [];
listData.forEach((value) => {
ddOptions.push({key:value.id,text:value.name})
});
return ddOptions;
}
}
LISTDATAWEBPART.TS
Modify the getPropertyPaneConfiguration method so that the dropdown uses our new method.
PropertyPaneDropdown('ListID', {
label: strings.ListNamePropertyLabel,
options: this.getListDropdownOptions()
}),
Run gulp serve, and check if you get the mock data in the Offline workbench!
Of course, in a real SharePoint environment, we don’t want these mock lists, but the actual
SharePoint lists in our current site. For this, we will use the EnvironmentType which we can get from
the @microsoft/sp-core-library module.
Let’s import both our current environment type and the enum to compare with.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
Loading SharePoint Data
181
LISTDATAWEBPART.TS
import {
Environment,
EnvironmentType
} from '@microsoft/sp-core-library';
Now we will use that environment to detect the environment type. To make this more reusable, let’s
move the service initialization to a private property.
LISTDATAWEBPART.TS
private _dataService: ISPDataService;
private get DataService() : ISPDataService {
if(!this._dataService){
if (Environment.type in [EnvironmentType.Local, EnvironmentType.Test]) {
this._dataService = new MockDataService();
} else {
this._dataService = new SharePointDataService(this.context);
}
}
return this._dataService;
}
private getLists(): ISPList[]{
let listData: ISPList[] = this.DataService.GetLists();
return listData;
}
The SharePointDataService, which we will use in live environments, is not implemented yet, so let’s
do that first. Add a new file SharePointDataService.ts to the services folder.
The SPHttpClient is the class we will use to make a request to SharePoint to get the lists on the site. If
we look at the get method, you see that it returns a Promise of an http response.
AJAX requests and promises are asynchronous, so we will have to return a promise of data, not
actual data. The result can then be processed by the caller of our service, once the request is
complete. As we will have to modify the getLists method signature, we will also have to modify our
service interface and the mock data service.
Let’s modify the interface first!
ISPDATASERVICE.TS
export interface ISPDataService{
}
getLists():Promise<ISPList[]>;
Now modify the mock data service. We are not doing an actual asynchronous request here, so let’s
create a dummy promise and resolve it at the end of the getLists method.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
182
Loading SharePoint Data
MOCKDATASERVICE.TS
public getLists(): Promise<ISPList[]> {
var mockData: ISPList[] = [
{ id: "1", name: "Announcements" },
{ id: "2", name: "Calendar" }
];
return Promise.resolve(mockData);
}
Time to implement the live service! We will need a SPHttpClient instance for this, so let’s get it
through a constructor. The get method also requires a configuration, for this we will import
SPHttpClient class from the @microsoft/sp-http module.
SHAREPOINTDATASERVICE.TS
import { ISPList } from '../interfaces/ISPList';
import { ISPDataService } from '../interfaces/ISPDataService';
import {
IWebPartContext
} from '@microsoft/sp-webpart-base';
import {
SPHttpClient,
SPHttpClientResponse
} from '@microsoft/sp-http';
export default class SharePointDataService implements ISPDataService {
constructor(public context: IWebPartContext) { }
public getLists(): Promise<ISPList[]> {
let requestUrl: string =
this.context.pageContext.web.absoluteUrl +
'/_api/web/lists?$filter=Hidden eq false and BaseType eq
0&$select=id,title';
}
}
return this.context.spHttpClient
.get(requestUrl, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => response.json())
.then((jsonData: any) => {
return jsonData.value.map((element) => {
return { id: element.Id, name: element.Title };
});
})
.catch((error) => {
console.log("Something went wrong!");
console.log(error);
return [];
});
Good stuff: now we have a mock data service and a real data service! Of course this will break our
web part code, as we didn’t return a promise before.
Very important to remember is that the loading of data through the http client happens
asynchronously. This means that our JavaScript will continue even if the promise has not resolved
yet. The effect will be that our dropdown will show up empty and our data will be loaded later and
thus not show up. We actually want the dropdown to load before our web part is rendered. For this
we can use the onInit method of the web part base class. Have a look at the definition:
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
Loading SharePoint Data
183
So let’s load the data in the onInit method and let’s keep into account the return of a promise! Inside
the ListDataWebPart class, add the following code.
LISTDATAWEBPART.TS
private _listDropDownOptions: IPropertyPaneDropdownOption[] = [];
protected onInit(): Promise<void>{
this.getLists()
.then((listData) => {
this._listDropDownOptions = this.getListDropdownOptions(listData);
});
return Promise.resolve<void>();
}
Modify the getLists and GetListDropdownOptions methods to make them work with our new
service.
private getLists(): Promise<ISPList[]>{
return this.DataService.getLists();
}
private getListDropdownOptions(listData:ISPList[]):
IPropertyPaneDropdownOption[]{
var ddOptions: IPropertyPaneDropdownOption[] = [];
listData.forEach((value) => {
ddOptions.push({key:value.id,text:value.name})
});
return ddOptions;
}
Next, modify the PropertyPaneDropdown options source
PropertyPaneDropdown('ListID', {
label: strings.ListNamePropertyLabel,
options: this._listDropDownOptions
}),
As a final step import the SharePointDataService
import SharePointDataService from '../../services/SharePointDataService';
11.8.3.1 TEST IN SHAREPOINT
Let’s now check in a real environment. Load your workbench in SharePoint online! This should have
been setup earlier. Ask your trainer in case you do not have a SharePoint Online workbench.
Make sure that your local gulp serve is still running and serving the web part.
Open up the following URL: 'https://your-sharepoint-site/_layouts/15/workbench.aspx'
If you do not have any SharePoint lists on this site, please create a few and add some data. For
instance an announcements lists, a calendar and a custom list.
Now add your web part and click the edit button. You should now see your lists in the dropdown! In
case of trouble, check your http traffic with i.e. Fiddler, make sure your http requests are successful!
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
184
Loading SharePoint Data
11.8.4
LOAD THE SELECTED SHAREPOINT LISTS ITEMS
Now that we can select a list, we want to load some actual list data!
There are two scenario’s when we want to load the SharePoint list items:
1.
The web part was already on the page and we want to load the items for the previously
selected list. We will do this inside the render method.
2.
The web part is in edit mode and the user selects a different list. Meaning a property
changes.
We will override the onPropertyPaneFieldChanged method from the BaseClientWebPart
class to catch this event.
Let’s extend our data service with a method to load list items. We will start with the interface of
course. We also need a new data interface for List Items. Add a new file ISPListItem.ts to the
interfaces folder.
ISPLISTITEM.TS
export interface ISPListItem {
id: number;
title: string;
url?: string;
}
ISPDATASERVICE.TS
Import the new interface and create a new method on the data service interface
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
Loading SharePoint Data
185
import {ISPList} from './ISPList';
import {ISPListItem} from './ISPListItem';
export interface ISPDataService{
getLists():Promise<ISPList[]>;
getListItems(ListID:string, MaxItems:number):Promise<ISPListItem[]>;
}
Now implement the method on both the mock and the live data service.
MOCKDATASERVICE.TS
import { ISPListItem } from '../interfaces/ISPListItem';
Inside the MockDataService class, implement the getListItems method. Let’s use a random array that
contains the number of elements we want to get from our service.
public getListItems(ListID: string, MaxItems: number): Promise<ISPListItem[]>
{
var mockData: ISPListItem[] = [];
for (let i = 0, max = MaxItems; i < max; i += 1) {
mockData.push({ id: i, title: "Item" + i });
}
return Promise.resolve(mockData);
}
SHAREPOINTDATASERVICE.TS
import { ISPListItem } from '../interfaces/ISPListItem';
Inside the SharePointDataService class, implement the getListItems method.
Notice that into the REST call we pass in our second property, the MaxItems, to limit the maximum
item count.
public getListItems(ListID: string, MaxItems: number): Promise<ISPListItem[]>
{
let requestUrl: string =
this.context.pageContext.web.absoluteUrl +
"/_api/web/lists(guid'" + ListID + "')/items/?$top=" + MaxItems +
"&$select=id,Title";
return this.context.spHttpClient
.get(requestUrl, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => response.json())
.then((jsonData: any) => {
return jsonData.value.map((element) => {
return { id: element.Id, title: element.Title };
});
}
})
.catch((error) => {
console.log("Something went wrong!");
console.log(error);
return [];
});
Let’s now get the list item data in the web part. Create a method loadListData. This method will first
get the data from the data service and then render it inside the web part.
LISTDATAWEBPART.TS
import { ISPListItem } from '../../interfaces/ISPListItem';
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
186
Loading SharePoint Data
private loadListItems() {
this.DataService
}
.getListItems(this.properties.ListID, this.properties.MaxItems)
.then((listItemData: ISPListItem[]) => {
this.renderListItems(listItemData);
});
The renderListItems method will generate the HTML for the list items and inject it into a container
with id ListItemContainer. Implement it like this:
private renderListItems(listItemData: ISPListItem[]) {
var html: string = '';
listItemData.forEach((item: ISPListItem) => {
html += `
<div class="${styles.listItem}">
<span class="ms-font-l">${item.id}</span>
&nbsp;-&nbsp;
<span class="ms-font-l">${item.title}</span>
</div>
`;
});
const listContainer: Element =
this.domElement.querySelector('#spListItemContainer');
listContainer.innerHTML = html;
}
Of course, we do not have a container with that id yet, so let’s modify the render method to change
the default HTML of our web part.
LISTDATAWEBPART.TS
public render(): void {
this.domElement.innerHTML = `
<div class="${ styles.listData }">
<div class="${ styles.container }">
...
<div id="spListItemContainer"></div>
...
</div>
</div>`;
}
To make our list data look decent, let’s add a little SASS/CSS:
LISTDATAWEBPART.MODULE.SCSS
Remove the .button part and modify/add the a and .listItem selectors.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
Loading SharePoint Data
187
.listData {
.container {
max-width: 700px;
margin: 0px auto;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0,
0.1);
}
.row {
padding: 20px;
}
a{
text-decoration: none;
}
.listItem {
background-color: #FFFFFF;
color: #333333;
vertical-align: center;
margin: 20px 0px;
box-shadow: none;
*zoom: 1;
padding: 10px 30px;
position: relative;
box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0,
0.1);
}
}
As a final step, we need to actually call the loadListItems method. We will do this from the render
method and from the onPropertyChanged method override.
First add the call at the end of the render method.
LISTDATAWEBPART.TS
public render(): void {
this.loadListItems();
}
Now override the onPropertyChange method from the webpart base class.
We’ll add some logging as well, for better debugging. The onPropertyChange method accepts a
string with the path of the attribute and the old and new value of the property. As we do not know
the type of the property, the any type is used to accept all types. From within the method call the
base class method using super to have the default behaviour.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
188
Loading SharePoint Data
LISTDATAWEBPART.TS
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any,
newValue: any): void{
super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
this.loadListItems();
}
Amazingly creative stuff . Let’s test our webpart again in SharePoint! Select one of the lists and
check if your data is loaded or not! Don’t forget to set your Maximum Items to more than 0!
In case you do not get any results, remember to check your http traffic, or use your browser
debugger to step through your code! Just open the ts file for debugging, not the packaged JavaScript.
11.8.5
TEST YOUR WEB PART!
This lab is now complete. You’ve earned a coffee!
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
Loading Libraries and/or Frameworks
189
12
LOADING LIBRARIES AND/OR FRAMEWORKS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
190
Loading Libraries and/or Frameworks
12.1
CONSIDERATIONS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
Build and Deploy a Framework solution
211
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
212
Build and Deploy a Framework solution
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
Build and Deploy a Framework solution
213
13.6
LAB DEPLOYING A FRAMEWORK CLIENT WEB PART
In this lab we will take a framework project and deploy it on our sharepoint online environment.
13.6.1
BEFORE YOU START
For this lab, we need the following:
-
An app catalog site collection must be available in our SharePoint Online environment
Create one if needed
-
A working client web part solution
13.6.2
CREATE A DEPLOYMENT LOCATION
Go into your sharepoint developer site and create a new Document Library, call it “SPFx”. In that
library, create a folder called WebPartFiles.
Grab the url of your new folder. (i.e.
https://{tenant}.sharepoint.com/sites/spxdev/SPFx/WebPartFiles ).
Let’s now use this folder as our resource location for the web part.
CONFIG/WRITE-MANIFESTS.JSON
{
"cdnBasePath":
"https://{tenant}.sharepoint.com/sites/spxdev/SPFx/WebPartFiles"
}
Open the solution configuration file and set the flag to include the bundle into the sppkg file
includeClientSideAssets -to false.
Also make sure that global deployment is enabled, by setting skipFeatureDeployment to true.
CONFIG/PACKAGE-SOLUTION.JSON
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-
solution.schema.json",
"solution": {
"name": "{your project name}",
"id": "62b7b99f-6956-4491-b9f1-90644b9c5b8f",
"version": "2.0.0.0",
"includeClientSideAssets": false,
"skipFeatureDeployment": true
},
"paths": {
"zippedPackage": "solution/loading-data.sppkg"
}
}
13.6.3
GENERATE THE WEB PART ASSET FILES
Run the following command in node command prompt from the root of your solution
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
214
Build and Deploy a Framework solution
gulp bundle --ship
This should package all files, and put them in the temp/deploy location.
Copy all these files to the SharePoint folder you created
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
Build and Deploy a Framework solution
215
13.6.4
GENERATE THE PACKAGE
Run the following command
gulp package-solution --ship
This will generate a .sppkg file in the sharepoint/solution folder
Deploy this .sppkg to your app catalog. Just upload it to the Apps For SharePoint library.
Check the global deployment checkbox and click deploy!
13.6.5
USE THE WEB PART
Now edit an existing or add a new page, and insert your web part. Add it to the page. Configure it
through the edit panel.
Save the page!
That’s
it!
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
216
Deploying SharePoint Artifacts
14
DEPLOYING SHAREPOINT ARTIFACTS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
226
SharePoint Framework and React
15.2
MVVM
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
227
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
228
SharePoint Framework and React
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
229
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
230
SharePoint Framework and React
15.3
SPFX BOOTSTRAPPING
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
231
15.4
COMPONENTS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
232
SharePoint Framework and React
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
233
15.5
WHAT IS JSX
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
234
SharePoint Framework and React
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
235
15.6
JAVASCRIPT EXPRESSIONS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
236
SharePoint Framework and React
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
237
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
238
SharePoint Framework and React
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
239
15.7
HTML TAGS VS REACT COMPONENTS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
240
SharePoint Framework and React
15.8
JSX GOTCHAS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
241
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
242
SharePoint Framework and React
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
243
15.9
COMPONENT PROPERTIES
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
244
SharePoint Framework and React
15.10
COMPONENT STATE
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
245
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
246
SharePoint Framework and React
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
247
15.11
INTERACTIVITY
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
248
SharePoint Framework and React
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
249
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
250
SharePoint Framework and React
15.12
MULTIPLE COMPONENTS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
251
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
252
SharePoint Framework and React
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
253
15.13
TRANSFERRING PROPS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
254
SharePoint Framework and React
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
255
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
256
SharePoint Framework and React
15.14
FORM COMPONENTS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
257
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
258
SharePoint Framework and React
15.15
COMPONENT LIFECYCLE
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
259
15.16
EXTRA
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
260
SharePoint Framework and React
15.17
LAB REACT COMPONENTS - LISTING THE SITE PERMISSIONS
In this lab we will focus on creating React components. We will use the Yeoman generator to create a
React project. The target of this project is to list all the permissions on the current site. When we
click one of the groups we will list the group members.
To get all the information we will use the SharePoint REST services.
To style the components we will use the available office ui fabric styles.
15.17.1 CREATING THE PROJECT
Start a node command prompt. Move to the folder (cd) where you want to create the project.
To create a new Framework project we will run the yeoman generator with the
“@microsoft/sharepoint” template.
c:\Labs>yo @microsoft/sharepoint
The SharePoint Client-side Solution Generator should now start!
Now let’s step through the wizard. Add the following details:
24. Solution name: SitePermissionsSolution
25. Files location: Pick “Create a subfolder with solution name” (use the arrow keys)
26. Baseline packages: SharePoint Online only
27. Feature deployment: y
28. Require permissions to access web APIs: N
29. Client-side component type: WebPart
30. Webpart name: ListSitePermissions
31. Webpart description: Displays the current site permissions
32. Framework: Pick “React
Check that there are no errors when creating the web part. Open up Visual Studio Code and run the
project by running the following commands within the newly created folder:
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
261
code .
gulp serve
15.17.2 MODIFY THE GENERATED WEB PART CLASS
We are not going to use any web part properties or translated labels so let’s remove the following
code
LISTSITEPERMISSIONSWEBPART.TS
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import * as strings from 'listSitePermissionsStrings';
Also, modify the getPropertyPaneConfiguration method
LISTSITEPERMISSIONSWEBPART.TS
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: []
};
}
Now, let’s remove the default description property from the web part interface
LISTSITEPERMISSIONSWEBPART.TS
export interface IListSitePermissionsWebPartProps {
description: string;
}
As you can see, this web part loads a single React component ListSitePermissions and injects it into
the DOM. In that main component however we do want to use the web part context. We need it to
get the current site url and the http client. We will modify the component properties, so we can pass
it in, and then set it from the web part code.
COMPONENTS/ILISTSITEPERMISSIONSPROPS.TS
import {
IWebPartContext
} from '@microsoft/sp-webpart-base';
import {
IListSitePermissionsWebPartProps
} from '../ListSitePermissionsWebPart';
export interface IListSitePermissionsProps extends
IListSitePermissionsWebPartProps {
context: IWebPartContext;
}
In the web part code, you should now see that our element cannot be initialised properly. We need
to modify the passed in properties. Remove description, add context.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
262
SharePoint Framework and React
LISTSITEPERMISSIONSWEBPART.TS
public render(): void {
const element: React.ReactElement<IListSitePermissionsProps> =
React.createElement(ListSitePermissions, {
context: this.context
});
ReactDom.render(element, this.domElement);
}
Modify the render method of the main component so that we can build the project.
LISTSITEPERMISSIONS.TSX
public render(): React.ReactElement<IListSitePermissionsProps> {
return (
<div className={styles.listSitePermissions}>
<div className={styles.container}>
Permissions loading!
</div>
</div>
);
}
We will not change this web part any more during this lab. Build your project and check for errors.
15.17.3 CREATING THE MAIN COMPONENT
The main component has already been generated for us at
src/webparts/ListSitePermissions/components/ListSitePermissions.tsx. We will keep this component
and use it as the root component of our web part. Later we will create two child components,
PermissionList and GroupDetails.
As this component is the parent component it will host the data, thus the state. Because we are using
TypeScript, we can make this state typed. For this we will first create some interfaces. We want to
store the permissionset of the current site.
Need more info on the REST and security structure we are going to use, look at the following link:
https://msdn.microsoft.com/en-us/library/office/dn531432.aspx
Structure:
RoleAssignment - /_api/web/roleassignments
-
Member - /_api/web/roleassignments/GetByPrincipalId(id)/member
o
User/Group
Group - /_api/Web/sitegroups/getbyid(id)/users
User
-
RoleDefinitionBindings -
/_api/web/roleassignments/GetByPrincipalId(id)/roledefinitionbindings
o
Role
We can bring all of this together with some expand statements:
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
263
/_api/web/roleassignments?$expand=Member,Member/Users,RoleDefinitionBindings&$select=Pr
incipalId,Member/Title,Member/ID,Member/PrincipalType,Member/Users/Title,RoleDefinitionBin
dings/Id,RoleDefinitionBindings/Name
Testing this REST call this is what we get back:
Let’s create interfaces to store this data. It’s important to have interface members with exactly the
same name and casing as in the http response, this will make things a lot easier in our code. Instead
of mapping everything manually we will just send the original json response to our components to
render our data.
First, create a new folder under src called interfaces.
Create a new file in this folder called PermissionInterfaces.ts and add the following code:
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
264
SharePoint Framework and React
/SRC/INTERFACES/PERMISSIONINTERFACES.TS
export interface ISPRoleAssignment{
PrincipalId:number;
Member:ISPMemberInfo;
RoleDefinitionBindings:ISPRoleDefinitionBinding[];
}
export interface ISPMemberInfo{
Id:number;
Title:string;
PrincipalType:MemberType;
Users?:ISPUser[];
}
export enum MemberType{
Group = 8,
User = 1
}
export interface ISPRoleDefinitionBinding{
Id:number;
Name:string;
}
export interface ISPUser{
Title:string;
}
Now that we have our data structures, we can use them to create the state for our main component.
The first thing we will need again is a state interface. That interface will contain our permission set.
Make sure you use the interface when defining the component.
Add the following:
LISTSITEPERMISSIONS.TSX
import { ISPRoleAssignment } from
'../../../../interfaces/PermissionInterfaces';
export interface IListSitePermissionsState {
permissions: ISPRoleAssignment[];
}
export default class ListSitePermissions extends
React.Component<IListSitePermissionsProps, IListSitePermissionsState> {
public render(): React.ReactElement<IListSitePermissionsProps> {
return (
<div className={styles.listSitePermissions}>
<div className={styles.container}>
Permissions loading!
</div>
</div>
);
}
}
Let’s add a constructor to set the initial state. Let’s also implement the componentDidMount
method to load the site permission set when our component is loaded. The IWebPartContext
interface needs to be imported.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
265
LISTSITEPERMISSIONS.TSX
import { IWebPartContext } from '@microsoft/sp-webpart-base';
export default class ListSitePermissions extends … {
constructor(props:{context:IWebPartContext}){
super(props);
//set initial state
this.state = { permissions: [] };
}
public componentDidMount() :void{
//we will set the data here! I needz the method!
}
}
Run or build the project and check that everything builds fine.
Hope everything works just fine? Impressive, isn’t it .
15.17.4 WRITE THE HTTP SERVICE
Before we continue, let’s write the http service class that will connect to the SharePoint REST
services.
Let’s actually get some data. For this we will create a separate code file, as this might be something
we will need in other components.
In the src folder add a new folder services. Add a new file and name it PermissionsHttpService.ts.
We will need a context object to access the http client, so add the following code:
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
266
SharePoint Framework and React
PERMISSIONSHTTPSERVICE.TS
import {
IWebPartContext
} from '@microsoft/sp-webpart-base';
export default class PermissionsHttpService {
private _context: IWebPartContext;
constructor(context:IWebPartContext){
this._context = context;
}
}
Let’s first implement a method that will give us the role assignment collection. This method will
return a collection of ISPRoleAssignment, so add the import for the interface as well.
PERMISSIONSHTTPSERVICE.TS
import { ISPRoleAssignment } from '../interfaces/PermissionsInterfaces';
import {
SPHttpClient, SPHttpClientResponse
} from '@microsoft/sp-http';
export default class PermissionsHttpService {
private _roleAssignmentUrl =
"/_api/web/roleassignments?$expand=Member,Member/Users,RoleDefinitionBindings&
$select=PrincipalId,Member/Title,Member/ID,Member/PrincipalType,Member/Users/T
itle,RoleDefinitionBindings/Id,RoleDefinitionBindings/Name";
public GetRoleAssignmentData(): Promise<ISPRoleAssignment[]> {
return this._context.spHttpClient
.get(
this._context.pageContext.web.absoluteUrl +
this._roleAssignmentUrl,
SPHttpClient.configurations.v1
)
.then((data:SPHttpClientResponse) => data.json() as
Promise<{value:ISPRoleAssignment[]}>)
.then(jsonData => jsonData.value)
.catch(err => {
console.log(err);
return [];
});
}
}
Notice in this case we return the json as is, we’re not mapping anything manually. Be aware this will
include the odata metadata and send it to our components. If you want to avoid this overhead, map
everything manually!
Great! Now let’s get back to our component!
15.17.5 SHOW THE DATA IN THE COMPONENT
Let’s set the state in the component and then show it in the interface!
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
267
LISTSITEPERMISSIONS.TSX
import PermissionsHttpService from '../../../services/PermissionsHttpService';
export default class ListSitePermissions
extends React.Component<IListSitePermissionsProps,
IListSitePermissionsState> {
constructor(props:{context:IWebPartContext}){
super(props);
//set initial state
this.state = {permissions: [] };
//set service
this._permissionsHttpService = new
PermissionsHttpService(this.props.context);
}
private
_permissionsHttpService: PermissionsHttpService;
public componentDidMount(): void {
this._permissionsHttpService.GetRoleAssignmentData().then(
(roleAssignments: ISPRoleAssignment[]) => {
console.log(roleAssignments);
this.setState({
permissions: roleAssignments
});
}
);
}
}
Good good. Let’s see if it works! Open your SharePoint Online Workbench and check the console
output!
This will not work in your local workbench!
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
268
SharePoint Framework and React
15.17.6 CREATING A PERMISSION OVERVIEW COMPONENT
We could show all that glorious data in our main component, but this lab is about react components
right . Let’s create a component that will display the permission set.
Add a new folder Permissions inside the components folder. In that folder create a new component
file, named PermissionList.tsx.
Let’s add the react component code and the property interface we will need! In this component we
will also use css and react css tools, so let’s import them already!
PERMISSIONLIST.TSX
import * as React from 'react';
import {css} from 'office-ui-fabric-react';
import styles from '../ListSitePermissions.module.scss';
import { ISPRoleAssignment, MemberType } from
'../../../../interfaces/PermissionInterfaces';
export interface IPermissionListProps {
permissions: ISPRoleAssignment[];
}
export default class PermissionList
extends React.Component<IPermissionListProps,{}>{
}
Implement the render method to show the permissionset.
PERMISSIONLIST.TSX
public render(): React.ReactElement<IPermissionListProps> {
//console.log("rendering");
var roles = this.props.permissions.map(
(roleAss:ISPRoleAssignment) => {
return (
<div>{roleAss.Member.Title}</div>
);
}
);
return (
<div className="ms-Grid ms-fontColor-black">
<div className="ms-Grid-row ms-font-xl ms-fontColor-
themePrimary">Who has access to this site?</div>
{roles}
</div>
);
}
That should be enough for now. Yes, we will make it look pretty in a moment!
15.17.7 ADD THE PERMISSION OVERVIEW COMPONENT TO THE MAIN COMPONENT
Now we can use the component by importing it. We set the permissionSet property through the
attributes.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
269
LISTSITEPERMISSIONS.TSX
import PermissionList from './Permissions/PermissionList';
public render(): React.ReactElement<IListSitePermissionsProps> {
return (
<div className={styles.listSitePermissions}>
<div className={styles.container}>
<PermissionList permissions={this.state.permissions} />
</div>
</div>
);
}
Check the output!
15.17.8 FINALIZE THE PERMISSION OVERVIEW COMPONENT
Now, we will add some css (sass) to make the component look good! We will also need to modify the
render method of course.
No good-looking output without styling, so let’s go and implement the custom styles first.
replace the contents of the existing file with this css:
LISTSITEPERMISSIONS.MODULE.SCSS
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
.listSitePermissions {
.container {
margin: 0px auto;
}
.row {
padding:3px;
cursor: pointer;
}
.element{
margin-right: 2px;
padding:8px 10px 2px;
color:white;
min-height:35px;
vertical-align: middle;
}
.inline{
margin-right: 5px;
padding: 2px 5px;
border:1px dashed white;
}
.icon{
font-size: 20px;
margin-right: 10px;
}
}
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
270
SharePoint Framework and React
Modify the render method to make each role assignment look good. We will add an icon (office-ui-
fabric) to show if it is a user or a group. Also, we’ll get the list of role bindings and render them in
html.
PERMISSIONLIST.TSX
public render(): React.ReactElement<IPermissionListProps> {
var roles = this.props.permissions.map(
(roleAss:ISPRoleAssignment) => {
var roleBindingsHTML = roleAss.RoleDefinitionBindings.map(element
=>
<span className={styles.inline}
key={element.Id}>{element.Name}</span>
);
return (
<div className={css('ms-Grid-row', styles.row)} role="row"
key={roleAss.PrincipalId}>
<div className={css('ms-Grid-col ms-u-sm11 ms-u-lg5 ms-
bgColor-themePrimary', styles.element)} >
<i className={css(`ms-Icon ms-Icon--
${roleAss.Member.PrincipalType === MemberType.User ? 'Contact':'Group'}`,
styles.icon)}></i>
{roleAss.Member.Title}
</div>
<div className={css('ms-Grid-col ms-u-sm11 ms-u-lg6 ms-
bgColor-themePrimary', styles.element)} >
{roleBindingsHTML}
</div>
</div>
);
}
);
return (
<div className="ms-Grid ms-fontColor-white">
<div className="ms-Grid-row ms-font-xl ms-fontColor-
themePrimary">Who has access to this site?</div>
{roles}
</div>
);
}
Test!
Aaaaah better…
That concludes the first part of this lab. Good job!
In the next part we will implement the code to select a group and display it’s members in a separate
component.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
271
If you were fast, and everyone is still hard at work, just keep going!
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
272
SharePoint Framework and React
15.18
VIEWING GROUP MEMBERS
Now that we can look at the permission set, we want to be able to select a group and show the
members. For this, we will add a second component.
First let’s implement the select logic on the PermissionList component!
15.18.1 ADD SELECT TO PERMISSIONLIST COMPONENT
Add an event property to the main component. This will be an optional value as we start without
selection.
PERMISSIONLIST.TSX
export interface IPermissionListProps {
permissions: ISPRoleAssignment[];
onRoleAssignmentSelect?: any;
}
Let’s trigger the property from a function. Add it to the component class
PERMISSIONLIST.TSX
private selectRoleAssignment(role:ISPRoleAssignment, event): void{
this.props.onRoleAssignmentSelect(role);
}
Final step: call the function when somebody clicks a data row!
PERMISSIONLIST.TSX
public render(): React.ReactElement<IPermissionListProps> {
return (
<div className={css('ms-Grid-row', styles.row)} role="row"
key={roleAss.PrincipalId} onClick={this.selectRoleAssignment.bind(this,
roleAss)}>
</div>
);
15.18.2 USE EVENT ON THE MAIN COMPONENT
The PermissionList item in the render method of ListSitePermissions is now supporting our new
property. Let’s handle the event! Notice the arrow function, this will make sure the event handler
runs in the context of the current component instance.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
273
LISTSITEPERMISSIONS.TSX
public render(): React.ReactElement<IListSitePermissionsProps> {
return (
<div className={styles.listSitePermissions}>
<div className={styles.container}>
<PermissionList permissionSet={this.state.permissionSet}
onRoleAssignmentSelect={(ra) => this.handleRoleAssignmentSelect(ra)} />
</div>
</div>
);
}
Now, let’s implement the handleRoleAssignmentSelect method. We will store the selected object in
the state, so let’s extend that first.
LISTSITEPERMISSIONS.TSX
export interface IListSitePermissionsState {
permissions: ISPRoleAssignment[];
selectedRoleAssignment?: ISPRoleAssignment;
}
Add this method inside the class:
private handleRoleAssignmentSelect(roleAssignment:ISPRoleAssignment): void{
console.log(roleAssignment);
this.setState({
selectedRoleAssignment:roleAssignment
});
}
Test your project in the SharePoint Online workbench!
Make sure you see the selected role assignment object in the console output.
15.18.3 CREATE THE GROUP DETAILS COMPONENT
Now that we have our selected group object, we want to show it’s members!
For this, we will create a new component. Add a new file to the components/permissions folder
named GroupDetails.tsx.
The properties will contain the selected role assignment and it’s users.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
274
SharePoint Framework and React
GROUPDETAILS.TSX
import * as React from 'react';
import { css } from 'office-ui-fabric-react';
import styles from '../ListSitePermissions.module.scss';
import { ISPUser, ISPRoleAssignment } from
'../../../../interfaces/PermissionInterfaces';
export interface IGroupDetailsProps {
selectedRoleAssignment?: ISPRoleAssignment;
}
export default class GroupDetails extends React.Component<IGroupDetailsProps,
{}>{
}
15.18.4 USE THE MEMBER DATA IN THE COMPONENT
Now, let’s render the user data!
GROUPDETAILS.TSX
public render(): React.ReactElement<IGroupDetailsProps> {
if (!this.props.selectedRoleAssignment ||
!this.props.selectedRoleAssignment.Member.Users) {
return <div />;
} else {
var users = this.props.selectedRoleAssignment.Member.Users.map((user:
ISPUser) =>
<div className={css('ms-Grid-col ms-u-sm11 ms-u-md3 ms-bgColor-
themePrimary', styles.element)} key={user.Title}>{user.Title}</div>
);
return (
<div className="ms-Grid ms-fontColor-white">
<div className="ms-Grid-row ms-u-sm11 ms-font-xl ms-fontColor-
themePrimary">Group Members</div>
<div className="ms-Grid-row">
{users}
</div>
</div>
);
}
}
15.18.5 ADD THE GROUP DETAILS COMPONENT TO MAIN COMPONENT
Now let’s use our new component. Add it to the main component.
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
SharePoint Framework and React
275
LISTSITEPERMISSIONS.TSX
import GroupDetails from './permissions/GroupDetails';
public render(): JSX.Element {
return (
<div className={styles.listSitePermissions}>
<div className={styles.container}>
<PermissionList permissionSet={this.state.permissionSet}
onRoleAssignmentSelect={this.handleRoleAssignmentSelect} />
<GroupDetails
selectedRoleAssignment={this.state.selectedRoleAssignment} />
</div>
</div>
);
}
Test!
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be
276
SASS
16
SASS
Copyright 2000- 2018 by U2U Training nv/sa, Belgium For use in U2U courses only. Visit www.u2u.be

Please do not attempt to print this document